/* ==========================================================
 * 1. 属性修饰符 → 控制「可选 / 必填 / 只读」
 * ========================================================== */

/**
 * 1. Partial<T>
 * 把 T 的**所有**属性变成可选（加 ?）
 * 场景：表单更新、补丁对象、递归深度拷贝
 */
type Partial<T> = { [K in keyof T]?: T[K] };

interface User {
  id: number;
  name: string;
  age: number;
}

type PartialUser = Partial<User>;
// 等价于 { id?: number; name?: string; age?: number; }

const updateUser: PartialUser = { name: 'John' }; // ✅ 只传 name 足够

/**
 * 2. Required<T>
 * 去掉全部 ?，恢复**严格必填**
 * 场景：确保配置完整性、校验 DTO
 */
type Required<T> = { [K in keyof T]-?: T[K] };

interface Config {
  url?: string;
  timeout?: number;
}

type RequiredConfig = Required<Config>; // { url: string; timeout: number }

/**
 * 3. Readonly<T>
 * 给所有属性加上 readonly 标记，**浅只读**
 * 场景：Redux/MobX 状态快照、函数式编程 —— 禁止直接 mutate
 */
type Readonly<T> = { readonly [K in keyof T]: T[K] };

type ROUser = Readonly<User>;
const u: ROUser = { id: 1, name: 'A', age: 18 };
// u.name = 'B'; // ❌ TS2540: 无法分配到 "name" ，因为它是只读属性

/* ==========================================================
 * 2. 字段筛选 → 从「大对象」里快速抠出 / 排除 想要的部分
 * ========================================================== */

/**
 * 4. Pick<T, K>
 * 只保留 K 中列出的键（白名单）
 * 场景：前端列表仅需要少量字段、GraphQL 子查询
 */
type Pick<T, K extends keyof T> = { [P in K]: T[P] };

type UserBase = Pick<User, 'id' | 'name'>; // { id: number; name: string; }

/**
 * 5. Omit<T, K>
 * 排除 K 中列出的键（黑名单）
 * 场景：隐藏敏感字段（密码、手机号）、后端内部字段
 */
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

type UserNoAge = Omit<User, 'age'>; // { id: number; name: string; }

/* ==========================================================
 * 3. 字典构造 → 用联合一次性生成键值对
 * ========================================================== */

/**
 * 6. Record<K, T>
 * 以联合 K 为键、T 为值的「同构」字典
 * 场景：路由参数、权限表、多语言资源包
 */
type Record<K extends keyof any, T> = { [P in K]: T };

type Roles = Record<string, boolean>; // 任意字符串键 → boolean
const roles: Roles = { admin: true, user: false };

// 精确键范围
type PageMeta = Record<'title' | 'desc', string>; // { title: string; desc: string; }

/* ==========================================================
 * 4. 联合类型操作 → 集合思维（剔除 / 保留 / 去 null）
 * ========================================================== */

/**
 * 7. Exclude<T, U>
 * 差集：T 里去掉**可赋给 U** 的成员
 */
type Exclude<T, U> = T extends U ? never : T;

type T0 = Exclude<'a' | 'b' | 'c', 'a'>; // 'b' | 'c'
type T1 = Exclude<string | number | (() => void), Function>; // string | number

/**
 * 8. Extract<T, U>
 * 交集：T 里保留**可赋给 U** 的成员
 */
type Extract<T, U> = T extends U ? T : never;

type T2 = Extract<'a' | 'b' | 'f', 'a' | 'x'>; // 'a'
type T3 = Extract<string | number | (() => void), Function>; // () => void

/**
 * 9. NonNullable<T>
 * 去掉 null & undefined；常用于 Promise 结果、数组元素
 */
type NonNullable<T> = T extends null | undefined ? never : T;

type T4 = NonNullable<string | number | undefined>; // string | number
type T5 = NonNullable<string[] | null>; // string[]

/* ==========================================================
 * 5. 函数世界 → 抽返回值 / 参数 / 解开 Promise
 * ========================================================== */

/**
 * 10. ReturnType<F>
 * 拿到函数**真正返回**的类型（推断 infer）
 * 场景：封装请求层时复用后端 DTO
 */
type ReturnType<T extends (...args: any) => any> =
  T extends (...args: any) => infer R ? R : any;

declare function f1(): { ok: boolean };
type FR = ReturnType<typeof f1>; // { ok: boolean }

/**
 * 11. Parameters<F>
 * 把参数列表拉成「元组」
 * 场景：装饰器、高阶函数转发参数
 */
type Parameters<T extends (...args: any) => any> =
  T extends (...args: infer P) => any ? P : never;

declare function f2(a: string, b: number): void;
type FP = Parameters<typeof f2>; // [a: string, b: number]

/**
 * 12. Awaited<T> (TS4.5+)
 * 递归解开 Promise / Thenable，直到非 Promise
 * 场景：封装 async 工具、与 ReturnType 组合
 */
type Awaited<T> = T extends PromiseLike<infer U> ? Awaited<U> : T;

declare function fetchUser(): Promise<User>;
type FU = Awaited<ReturnType<typeof fetchUser>>; // User

/* ==========================================================
 * 6. 字符串模板四兄弟 (TS4.1+) → 编译期大小写/首字母变换
 * ========================================================== */
type Uppercase<S extends string> = intrinsic;
type Lowercase<S extends string> = intrinsic;
type Capitalize<S extends string> = intrinsic;
type Uncapitalize<S extends string> = intrinsic;

type Event = 'click' | 'change';
type Handler = `on${Capitalize<Event>}`; // 'onClick' | 'onChange'

/* ==========================================================
 * 7. 冷门但有用（写库时会遇到）
 * ========================================================== */
type ThisParameterType<T> = intrinsic; // 抽出函数 this 类型
type OmitThisParameter<T> = intrinsic; // 去掉 this 参数后的新函数类型

/* ==========================================================
 * 8. 综合小练习 → 组合多个工具，一次成型
 * ========================================================== */
interface Product {
  id: number;
  name: string;
  price: number;
  desc: string;
}

// 只读、无价格、仅必要字段 → 给前端卡片组件
type ProductCard = Readonly<Pick<Omit<Product, 'desc'>, 'id' | 'name'>>;
// 等价于
// { readonly id: number; readonly name: string; }

export {}; // 模块化，防止全局变量冲突